package com.open4cn.simulator.device.datacolor;

import com.open4cn.simulator.connect.tcp.TCPServerConnector;
import com.open4cn.simulator.connect.tcp.handler.DispatcherHandler;
import com.open4cn.simulator.connect.tcp.handler.ReadBlockHandler;
import com.open4cn.simulator.connect.tcp.handler.ReadLogHandler;
import com.open4cn.simulator.connect.tcp.handler.WriteLogHandler;
import com.open4cn.simulator.connect.tcp.listenner.ConnectStatusFutureListener;
import com.open4cn.simulator.core.connector.ConnectAddress;
import com.open4cn.simulator.core.connector.IConnector;
import com.open4cn.simulator.core.device.DeviceInfo;
import com.open4cn.simulator.core.device.DeviceParameters;
import com.open4cn.simulator.core.device.DeviceStatus;
import com.open4cn.simulator.core.device.IDevice;
import com.open4cn.simulator.core.device.IDeviceFactory;
import com.open4cn.simulator.core.ext.DataColorStatus;
import com.open4cn.simulator.core.parser.IInstructionParser;
import com.open4cn.simulator.core.parser.InstructionParserChain;
import com.open4cn.simulator.device.AnswerManager;
import com.open4cn.simulator.device.DeviceStatusManager;
import com.open4cn.simulator.parser.Unknown;
import com.open4cn.simulator.parser.datacolor.dc600.A$00$Pattern;
import com.open4cn.simulator.parser.datacolor.dc600.B4RE010D;
import com.open4cn.simulator.parser.datacolor.dc600.F00000D6;
import com.open4cn.simulator.parser.datacolor.dc600.F00100D7;
import com.open4cn.simulator.parser.datacolor.dc600.GE00CC;
import com.open4cn.simulator.parser.datacolor.dc600.GI00D0;
import com.open4cn.simulator.parser.datacolor.dc600.H00A8;
import com.open4cn.simulator.parser.datacolor.dc600.HC00CB;
import com.open4cn.simulator.parser.datacolor.dc600.M$$Pattern;
import com.open4cn.simulator.parser.datacolor.dc600.R$00C$Pattern;
import com.open4cn.simulator.parser.datacolor.dc600.S00B3;
import com.open4cn.simulator.parser.datacolor.dc600.SX00EB;
import com.open4cn.simulator.parser.datacolor.dc600.W4RE0122;
import com.open4cn.simulator.protocol.datacolor.DataColorDecoder;
import com.open4cn.simulator.protocol.datacolor.DataColorEncoder;

import java.util.Arrays;
import java.util.List;

/**
 * @author yinxiaopeng
 * @version 1.0.0
 * @company 致景科技
 * @department 飞梭BU/研发
 * @description
 * @Email yinxiaopeng@zj.tech
 * @date 2022-04-30 16:36
 */
public class DataColor600Factory implements IDeviceFactory {


    @Override
    public IDevice build(DeviceParameters parameters) {
        DataColor600 dataColor600 = new DataColor600();
        dataColor600.setDeviceInfo(deviceInfo(parameters));
        dataColor600.setConnector(connector(dataColor600.getDeviceInfo()));
        return dataColor600;
    }


    /**
     * 组装datacolor600的设备info
     *
     * @param parameters
     * @return
     */
    private DeviceInfo<Object, DataColorStatus> deviceInfo(DeviceParameters parameters) {
        DeviceInfo<Object, DataColorStatus> deviceInfo = new DeviceInfo<>();
        deviceInfo.setId(parameters.getId());
        deviceInfo.setName(parameters.getName());
        deviceInfo.setBrand(parameters.getBrand());
        deviceInfo.setModel(parameters.getModel());
        deviceInfo.setDeviceStatus(deviceStatus(deviceInfo));
        deviceInfo.setConnectAddress(new ConnectAddress(parameters.getInteger(DCPredefinedAttributes.PORT)));
        return deviceInfo;
    }


    /**
     * 组装状态
     *
     * @param deviceInfo
     * @return
     */
    private DeviceStatus deviceStatus(DeviceInfo deviceInfo) {
        String deviceId = deviceInfo.getId();
        DeviceStatusManager deviceStatusManager = DeviceStatusManager.getInstance();
        DeviceStatus deviceStatus = deviceStatusManager.load(deviceId);
        if (null == deviceStatus) {
            deviceStatus = new DeviceStatus(deviceId, deviceInfo.getBrand(), deviceInfo.getModel(), new DataColorStatus());
        }
        deviceStatusManager.put(deviceId, deviceStatus);
        return deviceStatus;
    }


    /**
     * 组装datacolor600的通讯连接器
     *
     * @param deviceInfo
     * @return
     */
    private IConnector connector(DeviceInfo deviceInfo) {
        TCPServerConnector connector = new TCPServerConnector();
        connector.beforeDecod(new ReadLogHandler(deviceInfo.getName()));
        connector.beforeDecod(new ReadBlockHandler(deviceInfo.getDeviceStatus()));
        connector.decoder(DataColorDecoder.class);
        connector.afterDecod(new DispatcherHandler(chain(deviceInfo)));
        connector.encoder(DataColorEncoder.class);
        connector.afterEncod(new WriteLogHandler(deviceInfo.getName()));
        connector.addFutureListenner(new ConnectStatusFutureListener(connector.getConnectStatus()));
        return connector;
    }


    private InstructionParserChain chain(DeviceInfo deviceInfo) {
        DataColorStatus dataColorStatus = (DataColorStatus) deviceInfo.getDeviceStatus().getData();
        List<IInstructionParser> parsers = Arrays.asList(
                new S00B3(dataColorStatus),
                new M$$Pattern(dataColorStatus),
                new H00A8(dataColorStatus),
                new HC00CB(dataColorStatus),
                new R$00C$Pattern(dataColorStatus),
                new SX00EB(dataColorStatus),
                new A$00$Pattern(dataColorStatus),
                new GE00CC(dataColorStatus),
                new GI00D0(dataColorStatus),
                new F00000D6(dataColorStatus),
                new F00100D7(dataColorStatus),
                new B4RE010D(dataColorStatus),
                new W4RE0122(dataColorStatus),
                new Unknown()
        );
        manageAnswer(deviceInfo.getId(), parsers);
        return new InstructionParserChain(parsers);
    }


    private void manageAnswer(String deviceId, List<IInstructionParser> parsers) {
        AnswerManager answerManager = AnswerManager.getInstance();
        parsers.forEach(parser -> {
            answerManager.put(deviceId, parser.getAnswers());
        });
    }
}
